package com.ygu.user;

import com.ygu.user.dao.UserDao;
import com.ygu.user.service.adapter.TextBuilder;
import com.ygu.user.service.adapter.UserAdapter;
import com.ygu.websocket.domain.entity.User;
import com.ygu.websocket.srevice.WebSocketService;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.net.URLEncoder;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Component
public class WxMsgService {

    //微信调用回调
    @Value("${wx.mp.callback}")
    private String callback;
    @Resource
    private UserDao userDao;
    @Resource
    private WebSocketService webSocketService;

    /**
     * 用户的openId和前端登录场景code的映射关系
     */
    private static final String URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect";

    //维护的是临时的注册表CODE 和 OPENID 的关系
    private static final ConcurrentHashMap<String,Integer> WAITE_AUTHOURIZE = new ConcurrentHashMap<>();

    public WxMpXmlOutMessage scan(WxMpXmlMessage wxMpXmlMessage, WxMpService wxMpService) {
        try {
            //用于获取AccessToken
            String openId = wxMpXmlMessage.getFromUser();
            //为带参二维码里面的CODE
            String code = getEventKey(wxMpXmlMessage);
            log.info("扫码用户信息:{}    扫码事件:{} ",openId,code);
            //1.当用户扫码进来之后  判断该用户是否已经注册
            User user = userDao.getUserByOpenId(openId);
            //若是已经注册过并且授权过了 因为授权过的才会有头像 的用户则进行  则直接进行登入操作
            if(Objects.nonNull(user) && StringUtils.isBlank(user.getAvatar())){
                //传入code 是因为在登入的时候进行绑定channel 登入逻辑 通过code关联到我的channel
                webSocketService.scanLoginUser(user.getId(),code);
                return null;
            }
            //2.若未注册则进行注册操作
            if(Objects.isNull(user) || StringUtils.isBlank(user.getAvatar())){
                userDao.register(openId);
            }
            //最终 用户注册号了 要进行发送一个授权连接
            WAITE_AUTHOURIZE.put(openId,Integer.valueOf(code));
            //发送消息让前端知道 正在扫码授权流程
            webSocketService.waitAuthorize(code);
            //将URL 里面的appId 和 redirect_url 用于微信回调 进行替换 ( redirect_url )授权后重定向的回调链接地址， 请使用 urlEncode 对链接进行处理
            String authorizeUrl = String.format(URL, wxMpService.getWxMpConfigStorage().getAppId(), URLEncoder.encode(callback + "/wx/portal/public/callBack"));
            return TextBuilder.build("请点击登入授权: <a href=\"" + authorizeUrl + "\">登录</a> ",wxMpXmlMessage);
        }catch (Exception e){
            log.warn("出错啦！",e);
        }
        return TextBuilder.build("出错啦! 联系阿鑫 : <a href=\"" + "15280325871" + "\">联系号码</a> ",wxMpXmlMessage);

    }

    /**
     * 获取CODE
     * @param wxMpXmlMessage 微信回调回来的信息
     * @return 返回code
     */
    private String getEventKey(WxMpXmlMessage wxMpXmlMessage) {
        return wxMpXmlMessage.getEventKey().replace("qrscene_", "");
    }

    private void loginUser(Long id, String code) {

    }



    /**
     * 用户授权后 要补充其他用户信息  并且进行登入操作
     * @param userInfo 用户信息
     */
    public void authorized(WxOAuth2UserInfo userInfo) {
        String openid = userInfo.getOpenid();
        User user = userDao.getUserByOpenId(openid);
        Optional.ofNullable(user).ifPresent(param ->{
            fillUserInfo(user.getId(),userInfo);
        });

        //准备在用户授权之后 就要进行登入操作 我们就要获取到用户channel
        Integer result = WAITE_AUTHOURIZE.get(openid);
        String code = String.valueOf(result);
        //通过code 找到对应的channel 进行关联扫码登入
        webSocketService.scanLoginUser(user.getId(),code);
    }

    private void fillUserInfo(Long uid , WxOAuth2UserInfo userInfo) {
        User  user = UserAdapter.buildAuthorized(uid,userInfo);
        Optional.ofNullable(user).ifPresent(param ->{
            userDao.updateById(param);
        });
    }
}
